#include "Buffer.h"

#include <sys/uio.h>
#include <algorithm>
#include <unistd.h>

ssize_t Buffer::readFd(int fd, int *saveError)
{
    char extrabuf[65536];
    const size_t writeByte = writableBytes();

    iovec iov[2];
    iov[0].iov_base = beginWrite();
    iov[0].iov_len = writableBytes();
    iov[1].iov_base = extrabuf;
    iov[1].iov_len = sizeof extrabuf;

    const int iocnt = ((writableBytes() < sizeof(extrabuf)) ? 2 : 1);
    ssize_t n = readv(fd, iov, iocnt);

    if (n < 0)
    {
        *saveError = errno;
    }
    else if (static_cast<size_t>(n) <= writableBytes())
    {
        m_writeIndex += n;
    }
    else
    { // n > writableBytes() 空间不足,部分数据存储到了extrabuf中
        m_writeIndex = m_buffer.size();
        append(extrabuf);
    }
    return n;
}

// void Buffer::append(char* buf, size_t len) {
//     //确保空间足够
//     ensureWritableBytes(len);
//     //数据拷贝
//     std::copy(buf, buf+len, beginWrite());
//     //修改偏移量
//     m_writeIndex += len;
// }

void Buffer::append(std::string_view data)
{
    // 确保空间足够
    ensureWritableBytes(data.size());
    // 数据拷贝
    std::copy(data.data(), data.data() + data.size(), beginWrite());
    // 修改偏移量
    m_writeIndex += data.size();
}

void Buffer::ensureWritableBytes(size_t len)
{
    if (writableBytes() < len)
    {
        makeSpace(len);
    }
}

void Buffer::makeSpace(size_t len)
{
    // 情况一，预留空间和可写空间之和足够写入数据
    // 将可读数据前移，腾出可写空间
    // 情况二，预留空间和可写空间之和不足以写入数据
    // 对缓冲区扩容
    if (prependableBytes() + writableBytes() >= len + kCheapPrepend)
    {
        size_t readByte = readableBytes();
        std::copy(beginRead(), beginWrite(), begin() + kCheapPrepend);
        m_readIndex = kCheapPrepend;
        m_writeIndex = m_readIndex + readByte;
    }
    else
    {
        m_buffer.resize(m_writeIndex + len);
    }
}

ssize_t Buffer::writeFd(int fd, int *saveError)
{
    ssize_t n = write(fd, beginRead(), readableBytes());
    if (n < 0)
    {
        *saveError = errno;
    }
    return n;
}

void Buffer::retrieve(size_t len)
{
    if (len < readableBytes())
    {
        m_readIndex += len;
    }
    else
    {
        retrieveAll();
    }
}
void Buffer::retrieveAll()
{
    m_readIndex = kCheapPrepend;
    m_writeIndex = kCheapPrepend;
}

std::string Buffer::retrieveAsString(size_t len) {
    //TODO 这里是否需要判断len是否越界
    std::string res(beginRead(), len);
    retrieve(len);
    return res;
}
std::string Buffer::retrieveAllAsSting() {
    return retrieveAsString(readableBytes());
}